package edu.geo.containers.geomdomain;

import java.io.CharArrayWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.codehaus.jackson.map.ObjectMapper;

import com.vividsolutions.jts.geom.Coordinate;

import edu.geo.containers.GeoJson;
import edu.geo.containers.Json;
import edu.geo.containers.geom.impl.LineSegment;
import edu.geo.containers.geom.impl.Point;
import edu.geo.protocol.Properties;

/**
 * 
 * @author alejandro.sanchez
 *
 */
public class GeometricDomain implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -5031806506407489698L;
	
	//public static final String GEOJSON_TEMPLATE =  "{\"type\": \"GeometryCollection\",\"geometries\": [{0}]}";
	/**
	 * Identificador único del dominio geométrico.
	 */
	private int id;	
	
	/**
	 * Usuario creador del dominio geométrico
	 */
	private String user;
	
	/**
	 * Grilla asociada al dominio geométrico 
	 * 
	 */
	private Grid grid;
	
	/**
	 * Puntos contenidos en el dominio geométrico.
	 */
	private List<Point> points;
	
	/**
	 * Segmentos de línea contenidos en el dominio geométrico.
	 */
	private List<LineSegment> lineSegments;
	
	/**
	 * Indica si un dominio geométrico corresponde a un dominio válido o no. Valido indica
	 * si el dominio cumple las 4 condiciones de clausura de los dominios geométricos.
	 * @see edu.geo.geomdomain.GeometricDomainValidator
	 */
	private boolean valid; 
	
	private String gridOrigin;

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}

	public Grid getGrid() {
		return grid;
	}

	public List<Point> getPoints() {
		return points;
	}

	public void setPoints(List<Point> points) {
		this.points = points;
	}

	public List<LineSegment> getLineSegments() {
		return lineSegments;
	}

	public void setLineSegments(List<LineSegment> lineSegments) {
		this.lineSegments = lineSegments;
	}
	
	
	public EPointResult addPoint( Point point )
	{
		if (points == null)
		{
			points = new ArrayList<Point>();
		}
		if ( points.contains(point) )
		{
			return EPointResult.POINT_EXISTS;
		}
		else
		{
			points.add(point);
			return EPointResult.POINT_ADDED;
		}
	}
	
	
	public ELineSegmentResult addLineSegment( LineSegment lineSegment )
	{
		if (lineSegments == null)
		{
			lineSegments = new ArrayList<LineSegment>();
		}
		if ( lineSegments.contains(lineSegment) )
		{
			return ELineSegmentResult.LINE_SEGMENT_EXISTS;
		}
		else
		{
			lineSegments.add(lineSegment);
			return ELineSegmentResult.LINE_SEGMENT_ADDED;
		}
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public void setGrid(Grid grid) {
		this.grid = grid;
		if (grid != null)
		{
			gridOrigin = grid.getOrigin().toString();
		}
		else
		{
			gridOrigin = "";
		}
	}
	
	public String getGeomObjectsAsGeoJson()
	{
		
	  Json jsonFeatures= new Json(); 	
	  jsonFeatures.setName("GeometricDomainFeatures");
	  jsonFeatures.setType("FeatureCollection");
	  ArrayList<Json> featureList= new ArrayList<Json>();
      if(this.points!=null)
      {
    	  for(Point point:this.points)
    	  {
    		 Json feature = new Json();
    		 feature.setType("Feature");
    		 GeoJson geoJson= new GeoJson();
			 geoJson.setType("Point");
			 ArrayList<Double> coordinates = new ArrayList<Double>();
			 coordinates.add(point.getX());
			 coordinates.add(point.getY());
			 geoJson.setCoordinates(coordinates);
			 feature.setGeometry(geoJson);
			 Properties prp = new Properties();
			 prp.setId(point.getId()+"");
			 prp.setResult(""+point.getAsWKT());
			 feature.setProperties(prp);
			 featureList.add(feature);				
    	  }

      }
      
      if(this.lineSegments!=null)
      {
    	  for(LineSegment line:this.lineSegments)
    	  {
    		  Json feature= new Json();
			  feature.setType("Feature");
				GeoJson geoJson= new GeoJson();
				geoJson.setType("LineString");
				ArrayList<ArrayList<Double>> coordinates = new ArrayList<ArrayList<Double>>();
				Coordinate[] coords = line.getCoordinates();
				int numCoords=coords.length;
				for(int i =0;i<numCoords;i++)
				{
					ArrayList<Double> coord= new ArrayList<Double>();
					coord.add(coords[i].x);
					coord.add(coords[i].y);
					coordinates.add(coord);
				}
				geoJson.setCoordinates(coordinates);
				feature.setGeometry(geoJson);
				Properties prp = new Properties();
				prp.setId(""+line.getId());
				prp.setResult(""+line.getAsWKT());
				feature.setProperties(prp);
				featureList.add(feature);			
    	  }
    	  
      }
      jsonFeatures.setFeatures(featureList);
      return printGjson(jsonFeatures);
	}

	public boolean isValid() {
		return valid;
	}

	public void setValid(boolean valid) {
		this.valid = valid;
	}
	
	public String getGridOrigin()
	{
		return gridOrigin;
	}
	
	
	public String printGjson(Json json)
	{
		String strJson= null;
		
		ObjectMapper jsonMapper = new ObjectMapper();
		CharArrayWriter writer = new CharArrayWriter();
		try
		{
			jsonMapper.writeValue(writer, json);
			strJson=writer.toString();
		}
		catch (Exception e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return strJson;
	}
	
}
